package com.mytx.search.controller;


import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mytx.common.annotation.SerializedField;
import com.mytx.common.constant.Const;
import com.mytx.common.constant.Constant;
import com.mytx.common.pojo.CommonResult;
import com.mytx.common.pojo.RedisLock;
import com.mytx.common.utils.DateUtils;
import com.mytx.common.utils.EntityUtils;
import com.mytx.common.utils.IDUtils;
import com.mytx.mapper.DonationMapper;
import com.mytx.mapper.TaskMapper;
import com.mytx.mapper.TopicMapper;
import com.mytx.mapper.UserMapper;
import com.mytx.pojo.*;
import com.mytx.search.config.EsSearchClient;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@RestController
public class TaskController {
    private static final org.slf4j.Logger logger = LoggerFactory.getLogger(OrderController.class);


    @Autowired
    TaskMapper taskMapper;

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private TopicMapper topicMapper;

    @Autowired
    private DonationMapper donationMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private EsSearchClient searchClient;

    /**
     * 生成悬赏任务订单（ 接任务、揽活）
     *
     * @param topicId
     * @return
     */
    @PostMapping("/generateTask")
    public CommonResult generateTask(@RequestBody String topicId) {
        String uId = request.getHeader("uId");

        Topic topic = topicMapper.selectByPrimaryKey(topicId);
        if (topic.getStatus() == Constant.TOPIC_STATUS_REWARD_COMPLETE||topic.getStatus() == Constant.TOPIC_STATUS_REWARD_CANCEL) {
            return CommonResult.build(Constant.TOPIC_STATUS_ERROR, "该悬赏已经完结");
        }

        Boolean member = redisTemplate.opsForSet().isMember("TASK_RECEIVE_RECORD:" + topicId, uId);
        if (member) {
            return CommonResult.build(Constant.REWARD_TASK_RECEIVED, "你已经领取了该任务");
        }
        Task task = new Task();
        String id = IDUtils.genOrderItemId();
        task.setAmount(topic.getPrice());
        task.setId(id);
        task.setuId(uId);
        task.settId(topicId);
        task.setEmployerId(topic.getuId());
        task.setTitle(topic.getTitle());
        task.setStatus(Constant.TASK_STATUS_INIT);
        task.setCreated(new Date());
        taskMapper.insertSelective(task);
        int receiveTaskSize = topicMapper.incrementReceiveTaskSize(topicId);
        //更新到 ES
        Topic updateTopic = new Topic();
        updateTopic.setReceiveTaskSize(receiveTaskSize);
        updateTopic(topicId, updateTopic);

        redisTemplate.opsForValue().set(Constant.TASK_RECORD + id, task, 24, TimeUnit.HOURS);
        //在redis 保存一个 领取任务记录，避免反复领取
        redisTemplate.opsForSet().add("TASK_RECEIVE_RECORD:" + topicId, uId);
        //通知悬赏发布者 有人领取了任务 快来确认
        JSONObject info = new JSONObject();
        info.put("uId", topic.getuId());
        info.put("task", task);
        redisTemplate.convertAndSend(Constant.NOTIFY_TASK_INFO, info);

        return CommonResult.ok();
    }

    private void updateTopic(@RequestBody String topicId, Topic updateTopic) {
        String jsonString = JSONObject.toJSONString(updateTopic);
        UpdateRequest request = new UpdateRequest("topics", "topic", topicId);
        request.doc(jsonString, XContentType.JSON);
        UpdateResponse response = searchClient.update(request);
        if (response == null || response.getResult() == DocWriteResponse.Result.NOT_FOUND) {
            logger.error("generateTask:更新悬赏任务领取数量到es失败");
        }
    }

    /**
     * 确认 悬赏订单
     * 悬赏发布者确认由 赏金猎人发起的悬赏订单
     *
     * @return
     */
    @PostMapping("/confirmTask")
    public CommonResult confirmTask(@RequestBody String taskId) {

        RedisLock lock = new RedisLock(redisTemplate, Constant.TASK_LOCK + taskId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Object rewardOrderObject = redisTemplate.opsForValue().get(Constant.TASK_RECORD + taskId);
            if (rewardOrderObject == null) {
                return CommonResult.build(Constant.REWARD_TASK_INVALID, "悬赏订单已过期");
            }
            //判断悬赏任务是否已经结束
            Task task = (Task) rewardOrderObject;
            String topicId = task.gettId();
            Topic topic = topicMapper.selectByPrimaryKey(topicId);
            if(topic.getStatus()==Constant.TOPIC_STATUS_REWARD_COMPLETE){
                task.setStatus(Constant.TASK_STATUS_OTHER_ONE_COMPLETE);
                taskMapper.updateByPrimaryKeySelective(task);
                //清除缓存
                redisTemplate.delete(Constant.TASK_RECORD + taskId);
                return CommonResult.build(Constant.TOPIC_STATUS_ERROR,"对不起,已经有人完成了");
            }
            //判断悬赏任务是否已经取消了
            if(topic.getStatus() == Constant.TOPIC_STATUS_REWARD_CANCEL){
                task.setStatus(Constant.TASK_STATUS_REWARD_COMPLETE);
                redisTemplate.delete(Constant.TASK_RECORD + taskId);
                return CommonResult.build(Constant.REWARD_TOPIC_STATUS_ERROR,"您已经取消的悬赏任务");
            }
            task.setStatus(Constant.TASK_STATUS_CONFIRM);
            Date updated = new Date();
            task.setUpdated(updated);
            //在生成任务的时候已经保存进了mysql,现在只有更新即可
            Task updateTask = new Task();
            updateTask.setId(taskId);
            updateTask.setStatus(Constant.TASK_STATUS_CONFIRM);
            updateTask.setUpdated(updated);
            taskMapper.updateByPrimaryKeySelective(updateTask);
            redisTemplate.opsForValue().set(Constant.TASK_RECORD + taskId, task);
            JSONObject info = new JSONObject();
            info.put("uId", task.getuId());
            info.put("task", task);
            redisTemplate.convertAndSend(Constant.NOTIFY_TASK_INFO, info);
            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁内出错");
        } finally {
            lock.unlock();
        }
    }

    /**
     * 取消悬赏订单
     * 发布方取消的话，订单进入6天自动取消的状态，这期间 赏金猎人可以拒绝，因为可能 赏金猎人提供了有效的线索之后，悬赏发布方耍赖，，
     * 赏金猎人取消的话，该订单直接取消，进入终止状态，
     *
     * @param taskId
     * @return
     */
    @PostMapping("/cancelTask")
    public CommonResult cancelTask(@RequestBody String taskId) {
        String uId = request.getHeader("uId");
        RedisLock lock = new RedisLock(redisTemplate, Constant.TASK_LOCK + taskId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Object rewardOrderObject = redisTemplate.opsForValue().get(Constant.TASK_RECORD + taskId);
            if (rewardOrderObject == null) {
                return CommonResult.build(Constant.REWARD_TASK_INVALID, "悬赏订单无效");
            }
            Task task = (Task) rewardOrderObject;
            task.setUpdated(new Date());
            Integer originalStatus = task.getStatus();
            if (originalStatus == Constant.TASK_STATUS_EMPLOYEE_CANCEL) {
                return CommonResult.build(Constant.REWARD_TASK_STATUS_ERROR, "订单状态错误，已经取消");
            }
            boolean isEmployer = false;
            Date expiryDate = null;
            //判断是雇主取消悬赏订单还是雇佣者取消悬赏订单
            if (task.getEmployerId().equals(uId)) { //雇主取消悬赏订单
                isEmployer = true;
                if (originalStatus == Constant.TASK_STATUS_INIT) {
                    task.setStatus(Constant.TASK_STATUS_CONFIRM_FAIL);
                    //删除缓存
                    redisTemplate.delete(Constant.TASK_RECORD + taskId);
                } else {//设置6天的确认过期时间，到期雇佣者没有确认，默认 雇佣者同意取消

                    task.setStatus(Constant.TASK_STATUS_EMPLOYER_CANCEL);
                    expiryDate = DateUtils.getDate(6);

                    //expiryDate = DateUtils.addMinute(new Date(), 5);
                    task.setExpiryDate(expiryDate);
                    // String expiryDateKey = DateUtils.formatDate(expiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
                    String expiryDateKey = DateUtils.generateTaskKey(expiryDate);
                    redisTemplate.opsForSet().add(Constant.TASK_CANCEL_SET + expiryDateKey, task.getId());
                    //更新缓存
                    redisTemplate.opsForValue().set(Constant.TASK_RECORD + taskId, task);
                }
            } else {//雇佣者取消悬赏订单，合作结束，
                task.setStatus(Constant.TASK_STATUS_EMPLOYEE_CANCEL);
                if (originalStatus == Constant.TASK_STATUS_EMPLOYER_CANCEL) {
                    String expiryDateKey = DateUtils.generateTaskKey(task.getExpiryDate());

                    redisTemplate.opsForSet().remove(Constant.TASK_CANCEL_SET + expiryDateKey, task.getId());
                }
                //删除缓存
                redisTemplate.delete(Constant.TASK_RECORD + taskId);
            }

            taskMapper.updateByPrimaryKeySelective(task);
            JSONObject info = new JSONObject();
            if (isEmployer) {//雇主取消雇佣订单，通知雇佣者，雇佣者做出同意或者拒绝处理
                info.put("uId", task.getuId());
            } else {//雇佣者取消，通知雇主
                info.put("uId", task.getEmployerId());

            }
            info.put("task", task);
            redisTemplate.convertAndSend(Constant.NOTIFY_TASK_INFO, info);
            return CommonResult.ok(expiryDate);

        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁内出错");
        } finally {
            lock.unlock();
        }
    }

    /**
     * 雇佣者拒绝取消悬赏订单
     * 因为雇主拿到有效信息或者雇佣者完成任务（提供了服务）之后，雇主可能耍赖，取消订单
     *
     * @return
     */
    @PostMapping("/refuseCancelTask")
    public CommonResult refuseCancelTask(@RequestBody String taskId) {
        RedisLock lock = new RedisLock(redisTemplate, Constant.TASK_LOCK + taskId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Object rewardOrderObject = redisTemplate.opsForValue().get(Constant.TASK_RECORD + taskId);
            if (rewardOrderObject == null) {
                return CommonResult.build(Constant.REWARD_TASK_INVALID, "悬赏订单无效");
            }
            Task task = (Task) rewardOrderObject;

            if (task.getStatus() != Constant.TASK_STATUS_EMPLOYER_CANCEL) {
                return CommonResult.build(Constant.REWARD_TASK_STATUS_ERROR, "订单状态错误，只有雇主取消订单的情况下可以拒绝");
            }

            task.setStatus(Constant.TASK_STATUS_EMPLOYEE_REFUSE_CANCEL);
            task.setUpdated(new Date());
            taskMapper.updateByPrimaryKeySelective(task);
            //更新缓存
            redisTemplate.opsForValue().set(Constant.TASK_RECORD + taskId, task);
            //从自动取消订单的set中清除此订单id
            Date expiryDate = task.getExpiryDate();
            String expiryDateKey = DateUtils.generateTaskKey(expiryDate);
            redisTemplate.opsForSet().remove(Constant.TASK_CANCEL_SET + expiryDateKey, task.getId());
            //通知悬赏发布者 雇佣者拒绝了他的取消悬赏订单的请求
            JSONObject info = new JSONObject();
            info.put("uId", task.getEmployerId());
            info.put("task", task);
            redisTemplate.convertAndSend(Constant.NOTIFY_TASK_INFO, info);
            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁内出错");
        } finally {
            lock.unlock();
        }
    }

    /**
     * 雇佣者同意取消 悬赏订单
     *
     * @param taskId
     * @return
     */
    @PostMapping("/agreeCancelTask")
    public CommonResult agreeCancelTask(@RequestBody String taskId) {
        RedisLock lock = new RedisLock(redisTemplate, Constant.TASK_LOCK + taskId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Object rewardOrderObject = redisTemplate.opsForValue().get(Constant.TASK_RECORD + taskId);
            if (rewardOrderObject == null) {
                return CommonResult.build(Constant.REWARD_TASK_INVALID, "悬赏订单无效");
            }
            Task task = (Task) rewardOrderObject;
            if (task.getStatus() != Constant.TASK_STATUS_EMPLOYER_CANCEL) {
                return CommonResult.build(Constant.REWARD_TASK_STATUS_ERROR, "订单状态错误，只有雇主请求取消订单的情况下可以同意取消");
            }

            task.setStatus(Constant.TASK_STATUS_EMPLOYEE_AGREE_CANCEL);
            task.setUpdated(new Date());
            taskMapper.updateByPrimaryKeySelective(task);
            //从自动取消订单的set中清除此订单id
            Date expiryDate = task.getExpiryDate();
            String expiryDateKey = DateUtils.generateTaskKey(expiryDate);
            redisTemplate.opsForSet().remove(Constant.TASK_CANCEL_SET + expiryDateKey, task.getId());
            redisTemplate.delete(Constant.TASK_RECORD + taskId);
            //通知雇主， 雇佣者同意取消雇佣订单
            JSONObject info = new JSONObject();
            info.put("uId", task.getEmployerId());
            info.put("task", task);
            redisTemplate.convertAndSend(Constant.NOTIFY_TASK_INFO, info);
            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁内出错");
        } finally {
            lock.unlock();
        }
    }

    /**
     * 雇佣者 申请任务完成，进行悬赏订单结算
     * 等待 雇主确认 6天时间没做出处理，自动确认
     * 雇主确认后，结算订单
     * 雇主否定后，雇佣者可以再次发起
     *
     * @return
     */

    @PostMapping("/applyFinishTask")
    public CommonResult applyFinishTask(@RequestBody String taskId) {
        RedisLock lock = new RedisLock(redisTemplate, Constant.TASK_LOCK + taskId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Object rewardOrderObject = redisTemplate.opsForValue().get(Constant.TASK_RECORD + taskId);
            if (rewardOrderObject == null) {
                return CommonResult.build(Constant.REWARD_TASK_INVALID, "悬赏订单无效");
            }
            //判断悬赏任务是否已经结束
            Task task = (Task) rewardOrderObject;
            String topicId = task.gettId();
            Topic topic = topicMapper.selectByPrimaryKey(topicId);
            if(topic.getStatus()==Constant.TOPIC_STATUS_REWARD_COMPLETE){
                task.setStatus(Constant.TASK_STATUS_OTHER_ONE_COMPLETE);
                taskMapper.updateByPrimaryKeySelective(task);
                //清除缓存
                redisTemplate.delete(Constant.TASK_RECORD + taskId);
                return CommonResult.build(Constant.TOPIC_STATUS_ERROR,"悬赏任务结束");
            }
            task.setStatus(Constant.TASK_STATUS_APPLY_FINISH_TASK);
            task.setUpdated(new Date());
            Date expiryDate = DateUtils.getDate(6);

           // expiryDate = DateUtils.addMinute(new Date(), 5);
            task.setExpiryDate(expiryDate);
            taskMapper.updateByPrimaryKeySelective(task);
            //  String expiryDateKey = DateUtils.formatDate(expiryDate, DateUtils.DATE_FORMAT_DATE_HOUR);
            String expiryDateKey = DateUtils.generateTaskKey(expiryDate);
            redisTemplate.opsForSet().add(Constant.TASK_FINISH_SET + expiryDateKey, taskId);
            //更新缓存
            redisTemplate.opsForValue().set(Constant.TASK_RECORD + taskId, task);

            //通知雇主， 雇佣者申请完成任务，进行悬赏订单结算
            JSONObject info = new JSONObject();
            info.put("uId", task.getEmployerId());
            info.put("task", task);
            redisTemplate.convertAndSend(Constant.NOTIFY_TASK_INFO, info);

            return CommonResult.ok(expiryDate);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁内出错");
        } finally {
            lock.unlock();
        }
    }


    /**
     * 雇主拒绝雇佣者的任务完成申请
     * 不认可 雇佣者提供的服务
     *
     * @return
     */
    @PostMapping("/refuseApplyFinish")
    public CommonResult refuseApplyFinish(@RequestBody String taskId) {

        RedisLock lock = new RedisLock(redisTemplate, Constant.TASK_LOCK + taskId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Object rewardOrderObject = redisTemplate.opsForValue().get(Constant.TASK_RECORD + taskId);
            if (rewardOrderObject == null) {
                return CommonResult.build(Constant.REWARD_TASK_INVALID, "悬赏订单无效");
            }

            Task task = (Task) rewardOrderObject;
            if (task.getStatus() != Constant.TASK_STATUS_APPLY_FINISH_TASK) {
                return CommonResult.build(Constant.REWARD_TASK_STATUS_ERROR, "订单状态错误，只有申请完成任务的情况下可以拒绝申请");
            }
            task.setStatus(Constant.TASK_STATUS_EMPLOYER_REFUSE_FINISH_APPLY);
            task.setUpdated(new Date());
            taskMapper.updateByPrimaryKeySelective(task);
            //从申请任务完成的set中清除此订单id
            Date expiryDate = task.getExpiryDate();
            String expiryDateKey = DateUtils.generateTaskKey(expiryDate);
            redisTemplate.opsForSet().remove(Constant.TASK_FINISH_SET + expiryDateKey, task.getId());
            //更新缓存
            redisTemplate.opsForValue().set(Constant.TASK_RECORD + taskId, task);
            //通知雇佣者 任务完成申请已经被拒绝
            JSONObject info = new JSONObject();
            info.put("uId", task.getuId());
            info.put("task", task);
            redisTemplate.convertAndSend(Constant.NOTIFY_TASK_INFO, info);
            return CommonResult.ok();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁内出错");
        } finally {
            lock.unlock();
        }
    }


    /**
     * 雇主确认任务完成
     * 整个悬赏订单完成
     *
     * @return
     */
    @Transactional
    @PostMapping("/confirmTaskFinish")
    public CommonResult confirmTaskFinish(@RequestBody String taskId) {
        String loginUserId = request.getHeader("uId");

        RedisLock lock = new RedisLock(redisTemplate, Constant.TASK_LOCK + taskId);
        try {
            if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Object rewardOrderObject = redisTemplate.opsForValue().get(Constant.TASK_RECORD + taskId);
            if (rewardOrderObject == null) {
                return CommonResult.build(Constant.REWARD_TASK_INVALID, "悬赏订单无效");
            }
            Task task = (Task) rewardOrderObject;
            if (task.getStatus() != Constant.TASK_STATUS_APPLY_FINISH_TASK) {
                return CommonResult.build(Constant.REWARD_TASK_STATUS_ERROR, "订单状态错误，只有申请完成任务的情况下可以确认申请");
            }
            String topicId = task.gettId();
            Topic topic = topicMapper.selectByPrimaryKey(topicId);
            if (topic.getStatus() == Constant.TOPIC_STATUS_REWARD_COMPLETE) {
                task.setStatus(Constant.TASK_STATUS_OTHER_ONE_COMPLETE);
                taskMapper.updateByPrimaryKeySelective(task);
                //清除缓存
                redisTemplate.delete(Constant.TASK_RECORD + taskId);
                return CommonResult.build(Constant.TOPIC_STATUS_ERROR, "已经有人完结了悬赏任务");
            }
            topic.setStatus(Constant.TOPIC_STATUS_REWARD_COMPLETE);
            Date updated = new Date();
            topic.setUpdated(updated);
            topicMapper.updateByPrimaryKeySelective(topic);
            task.setStatus(Constant.TASK_STATUS_CONFIRM_FINISH);
            task.setUpdated(updated);
            taskMapper.updateByPrimaryKeySelective(task);

            BigDecimal reward = topic.getPrice();
            BigDecimal donationBalance = topic.getDonationBalance();//赏金
            BigDecimal totalMoney = reward.add(donationBalance);
            String targetUserId = task.getuId();
            BigDecimal targetUserMysqlBalance = userMapper.incrementBalance(targetUserId, totalMoney);
            //将捐赠赏金记录设置为不可撤回
            String orderId = topic.getId();
            DonationExample donationExample = new DonationExample();
            DonationExample.Criteria donationCriteria = donationExample.createCriteria();
            donationCriteria.andOIdEqualTo(orderId);
            Donation donation = new Donation();
            donation.setStatus(Constant.DONATION_STATUS_COULD_NOT_REVOKE);
            donationMapper.updateByExampleSelective(donation,donationExample);
            User user = userMapper.payV2(loginUserId, reward, reward);
            redisTemplate.opsForHash().put(Constant.USER_SESSION + targetUserId, Constant.BALANCE, targetUserMysqlBalance);
            redisTemplate.opsForHash().putAll(Constant.USER_SESSION + loginUserId, EntityUtils.objectToMap_v1(user));
            logger.info("employerConfirmTaskFinish:悬赏任务结算，雇佣者余额增加 ，uId:{},amount:{},balance:{}", targetUserId, totalMoney, targetUserMysqlBalance);
            logger.info("employerConfirmTaskFinish:悬赏任务结算，雇主余额减少 ，uId:{},amount:{},balance:{}", loginUserId, reward, user.getBalance());
            logger.info("employerConfirmTaskFinish:悬赏任务结算，雇主保证金减少 ，uId:{},amount:{},deposit:{}", loginUserId, reward, user.getDeposit());
            //将捐赠的赏金给到雇佣者
            //从申请任务完成的set中清除此订单id
            String expiryDateKey = DateUtils.generateTaskKey(task.getExpiryDate());
            redisTemplate.opsForSet().remove(Constant.TASK_FINISH_SET + expiryDateKey, task.getId());
            //清除缓存
            redisTemplate.delete(Constant.TASK_RECORD + taskId);
            //更新到 ES
            Topic updateTopic = new Topic();
            updateTopic.setStatus(Constant.TOPIC_STATUS_REWARD_COMPLETE);
            updateTopic(topicId, updateTopic);
            //通知雇佣者 任务完成申请已经通过确认
            JSONObject info = new JSONObject();
            info.put("uId", targetUserId);
            info.put("task", task);
            redisTemplate.convertAndSend(Constant.NOTIFY_TASK_INFO, info);
            return CommonResult.ok(user);
        } catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁内出错");
        } finally {
            lock.unlock();
        }
    }

    /**
     * 任务发布者取消悬赏主题
     * @param topicId
     * @return
     */
    @Transactional
    @PostMapping("/cancelOffeTopic")
    public CommonResult cancelOffeTopic(@RequestBody String  topicId){
        //1.获取当前悬赏任务的发布者
        String issueUserId = request.getHeader("uId");
        logger.info("cancelOffeTopic:取消任务的用户id:{},悬赏主题的id:{}",issueUserId,topicId);
        //2.根据topicId获取接受了发布任务
        RedisLock lock = new RedisLock(redisTemplate, Constant.TASK_LOCK + topicId);
        try {
             if (!lock.lock()) {
                return CommonResult.build(Constant.GET_LOCK_FAIL, "获取锁失败");
            }
            Topic topic = topicMapper.selectByPrimaryKey(topicId);
             //判断悬赏主题是否已经撤销了
            if(topic.getStatus()==Constant.TOPIC_STATUS_REWARD_CANCEL){
                return CommonResult.build(Constant.REWARD_TOPIC_ALREADY_CANCEL,"悬赏主题已经取消了,不可重复取消");
            }
            TaskExample taskExample = new TaskExample();
            TaskExample.Criteria criteria = taskExample.createCriteria();
            criteria.andTIdEqualTo(topicId);
            List<Task> taskList = taskMapper.selectByExample(taskExample);
            //3.判断悬赏任务下面是否已经有人接受了任务
            for (Task task : taskList) {
                Integer taskStatus = task.getStatus();
                if (Constant.TASK_STATUS_CONFIRM == taskStatus || Constant.TASK_STATUS_EMPLOYER_CANCEL == taskStatus || Constant.TASK_STATUS_EMPLOYEE_REFUSE_CANCEL == taskStatus
                        || Constant.TASK_STATUS_APPLY_FINISH_TASK == taskStatus || Constant.TASK_STATUS_EMPLOYER_REFUSE_FINISH_APPLY == taskStatus) {
                    // 如果有人接受了任务，则不能取消任务
                    logger.info("cancelOffeTopic:取消的悬赏主题下面还有未被处理的任务,不能取消认为");
                    return CommonResult.build(Constant.REWARD_TOPIC_STATUS_ERROR, "您还有没有被处理的任务,不能取消任务");
                }
            }

            List<String>userIdList=new ArrayList<>();
            //4.根据发布主题topicId获取到捐赠的赏金
            DonationExample donationExample = new DonationExample();
            DonationExample.Criteria donationCriteria = donationExample.createCriteria();
            donationCriteria.andOIdEqualTo(topicId);
            List<Donation> donationList = donationMapper.selectByExample(donationExample);
            //5.将捐赠的赏金返回给捐赠的用户
            for (Donation donation : donationList) {
                String userId = donation.getmId();
                BigDecimal amount = donation.getAmount();
                User user = userMapper.incrementBalanceAndReduceDonationAmount(userId, amount);
                redisTemplate.opsForHash().putAll(Constant.USER_SESSION + userId,EntityUtils.objectToMap_v1(user));
                logger.info("cancelOffeTopic:取消悬赏:将捐赠金返回给捐赠者:userId:{},返回金额:amount:{},balance:{},donationAmount:{}，donationId:{}",userId,amount,user.getBalance(),user.getDonationAmount(),donation.getId());
            }
            //6.将捐赠的赏金设置为已经撤回了
            Donation donation = new Donation();
            donation.setStatus(Constant.DONATION_STATUS_ALREADY_REVOKE);
            donationMapper.updateByExampleSelective(donation, donationExample);
            logger.info("cancelOffeTopic:将捐赠的赏金已经设置为拆回状态");
            //7.根据topicId获取到发布的主题
            logger.info("cancelOffeTopic:悬赏任务结算:已经全部将捐赠金返回给捐赠者们:topid:{},deposit:{}",topicId,topic.getDonationBalance());
            //8.将发布者的保证金减少,并修改缓存中的数据
            BigDecimal reduceDeposit = userMapper.reduceDeposit(issueUserId, topic.getPrice());
            redisTemplate.opsForHash().put(Constant.USER_SESSION + issueUserId, Constant.DEPOSIT, reduceDeposit);
            logger.info("cancelOffeTopic:悬赏任务结算:发布者的保证金减少,uid:{},price:{},reduceDeposit:{},topicId:{}",issueUserId,topic.getPrice(),reduceDeposit,topicId);
            //9.将接受的任务设置为发布者取消状态
            Task task = new Task();
            task.setStatus(Constant.TASK_STATUS_REWARD_COMPLETE);
            taskMapper.updateByExampleSelective(task,taskExample);
            for (Task task1: taskList) {
                task1.setStatus(Constant.TASK_STATUS_REWARD_COMPLETE);
                redisTemplate.delete(Constant.TASK_RECORD + task1.getId());
            }
            //10.将悬赏的任务设置为已经取消了
            Topic newTopic = new Topic();
            newTopic.setStatus(Constant.TOPIC_STATUS_REWARD_CANCEL);
            //将悬赏的任务的状态更新到ES中
            updateTopic(topicId, newTopic);
            newTopic.setId(topicId);
            topicMapper.updateByPrimaryKeySelective(newTopic);
            if (userIdList.size()!=0){
            //通知前端刷新捐赠用户的余额
            JSONObject info = new JSONObject();
            info.put("userIdList", userIdList);
            redisTemplate.convertAndSend(Constant.NOTIFY_SYNC_USER_INFO,info);
            }
            return CommonResult.ok(reduceDeposit);
        }catch (InterruptedException e) {
            e.printStackTrace();
            return CommonResult.build(Constant.UNKNOWN_ERROR, "锁内出错");
        } finally {
            lock.unlock();
        }
    }

    @PostMapping("/syncData")
    public CommonResult syncData(@RequestBody String taskId) {
        Object taskObject = redisTemplate.opsForValue().get(Constant.TASK_RECORD + taskId);
        if (taskObject != null) {
            return CommonResult.ok(taskObject);
        }
        Task task = taskMapper.selectByPrimaryKey(taskId);
        return CommonResult.ok(task);
    }


    @PostMapping("/queryReceiveTask")
    public CommonResult queryReceiveTask(@RequestBody Map<String, Object> info) {
        String uId = request.getHeader("uId");
        int page = 1;
        int size = 10;
        if (info.containsKey("page")) {
            page = (int) info.get("page");
        }
        if (info.containsKey("size")) {
            size = (int) info.get("size");
        }

        TaskExample example = new TaskExample();
        example.setOrderByClause("updated DESC,created DESC");
        TaskExample.Criteria criteria = example.createCriteria();
        criteria.andUIdEqualTo(uId);
        PageHelper.startPage(page, size);
        List<Task> orders = taskMapper.selectByExample(example);//貌似用不着关联查询
        PageInfo<Task> offerPageInfo = new PageInfo<>(orders);
        return CommonResult.ok(offerPageInfo);
    }

    @PostMapping("/queryPublishTask")
    public CommonResult queryPublishTask(@RequestBody Map<String, Object> info) {
        String uId = request.getHeader("uId");
        int page = 1;
        int size = 10;
        if (info.containsKey("page")) {
            page = (int) info.get("page");
        }
        if (info.containsKey("size")) {
            size = (int) info.get("size");
        }

        TaskExample example = new TaskExample();
        example.setOrderByClause("updated DESC,created DESC");
        TaskExample.Criteria criteria = example.createCriteria();
        criteria.andEmployerIdEqualTo(uId);
        PageHelper.startPage(page, size);
        List<Task> orders = taskMapper.selectByExample(example);//貌似用不着关联查询
        PageInfo<Task> offerPageInfo = new PageInfo<>(orders);
        return CommonResult.ok(offerPageInfo);
    }


}

